/** @module util */

export default {

    /**
     * 类型检测
     * @param {*} item 待检测数据
     */
    checkType(item) {
        const classType = {};
        const toString = Object.prototype.toString;
        // 生成classType映射
        ['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp',
            'Object', 'Error', 'Symbol', 'Map', 'Set', 'WeakSet', 'WeakMap'
        ].map((item) => {
            classType[`[object ${item}]`] = item.toLowerCase();
        });
        const _checkType = (obj) => {
            if (obj == null) {
                return `${obj}`;
            }
            return typeof obj === 'object' || typeof obj === 'function' ?
                classType[toString.call(obj)] || 'object' :
                typeof obj;
        };
        return _checkType(item);
    },

    /**
     * 判断给定的参数是否为对象类型
     * @param { any } obj - 被判断的参数
     */
    isObject: function(obj) {
        return this.checkType(obj) === 'object';
    },
    
    /**
     * equal: _str1 == _str2, big: _str1 > _str2, small: _str1 < _str2
     * @param {string} _str1 - 版本号，形如 1.0.0
     * @param {string} _str2 - 版本号，形如 1.0.0
     * @return {string} - 值域：equal、big、small
     */
    versionStrCompare(_str1, _str2) {
        let _strArrToInt = function(_arr) {
            for (let i = 0; i < _arr.length; i++) {
                // 不是数值类型保持原样
                if (_arr[i] >= 0) {
                    _arr[i] = parseInt(_arr[i], 10);
                }
            }
        };
        _str1 = _str1 + '';
        _str2 = _str2 + '';
        let _ifBig = '';
        if (_str1 === _str2) {
            _ifBig = 'equal';
        } else {
            let _arr1 = _str1.split('.');
            let _arr2 = _str2.split('.');
            _strArrToInt(_arr1);
            _strArrToInt(_arr2);
            let _len = _arr1.length;
            if (_arr2.length > _arr1.length) {
                _len = _arr2.length;
            }
            for (let i = 0; i < _len; i++) {
                if ((_arr1[i] || 0) > (_arr2[i] || 0)) {
                    _ifBig = 'big';
                    break;
                } else if ((_arr1[i] || 0) < (_arr2[i] || 0)) {
                    _ifBig = 'small';
                    break;
                }
            }
        }
        return _ifBig;
    },

    /**
     * 补齐位数，比如1要补齐到2位，结果就是 01
     * @param {number} number - 要补齐的数字本身
     * @param {number} count - 数字的位数，2位数、3位数类似这种
     * @param {string} feature - 用于补齐位数的特征，默认是0
     * @return {string}
     */
    paddingNumber(number, count, feature) {

        let c = count || 2;
        let f = feature || '0';
        let template = [];

        for (let i = 0; i < c; i++) {
            template.push(f);
        }

        let numStr = `${number}`;
        let len = numStr.length;

        if (len > c) {
            throw {
                message: '数字不能超出指定的位数'
            };
        } else {
            for (let i = len - 1, j = template.length - 1; i >= 0; i--, j--) {
                template[j] = numStr[i];
            }
        }
        return template.join('');
    },

    /**
     * 把一个数字转换为16进制
     * @param {number} number - 需要转换为16进制的10进制数字
     * @return {string}
     */
    toHexadecimal(number) {
        if (typeof number === 'number' && number >= 0) {
            return parseInt(number, 10).toString(16);
        } 
        throw {
            message: '只支持正数的处理'
        };
    },

    /**
     * 把对象放到数组中, 空对象返回空数组, 如果是数组则直接返回
     * @param {object} obj - 传入的对象参数
     * @return {object}
     */
    wrapObjToArray(_obj) {
        if (!Array.isArray(_obj)) {
            if (this.isEmpty(_obj)) {
                _obj = [];
            } else if (typeof(_obj) === 'object') {
                _obj = [_obj];
            }
        }
        return _obj;
    },

    /**
     * 拷贝对象s到目标t上
     * @param {object} t - 目标
     * @param {object} s - 源对象
     * @return {undefined}
     */
    copy(t, s) {
        for (let p in s) {
            if (typeof s[p] === 'object' && typeof t[p] === 'object') {
                this.copy(t[p], s[p]);
            } else {
                //直接赋值
                t[p] = s[p];
            }
        }
    },

    /**
     * 将源对象拷贝到目标对象
     * @param { object }target - 目标对象
     * @param { object }source - 原对象
     * @return {*}
     */
    assign: function(target, source) {
        let _this = this;
        if (typeof target !== 'object' || typeof source !== 'object') {
            return {};
        } 
        //调用递归函数
        _this.copy(target, source);

        return target;
    },

    /**
     * 判断数组是否包含item
     * @param {array} arr - 原始数组
     * @param {*} item - 传入的值
     * @param {function} eq - 判断传入的值是否相等的算法
     * @return {number}
     */
    contains: function(arr, item, eq) {
        let equal = eq || function(a, b) {
            return a === b;
        };
        let len = arr.length;
        for (let i = 0; i < len; i++) {
            if (equal(arr[i], item)) {
                return i;
            }
        }
        return -1;
    },

    /**
     * 判断comparedVersion是否低于基准版本号baseVersion
     * @param {string} comparedVersion - 0.4.4
     * @param {string} baseVersion - 1.0.0
     * @return {boolean}
     */
    belowVersion(comparedVersion, baseVersion) {
        let comparedVersions = comparedVersion.split('.');
        let baseVersions = baseVersion.split('.');

        for (let i = 0, len = comparedVersions.length; i < len; i++) {
            comparedVersions[i] = parseInt(comparedVersions[i], 10);
        }
        for (let i = 0, len = baseVersions.length; i < len; i++) {
            baseVersions[i] = parseInt(baseVersions[i], 10);
        }

        let i = 0,
            below = false;
        while (i < baseVersions.length) {
            let cVersion = comparedVersions[i] || 0;
            if (cVersion < baseVersions[i]) {
                below = true;
                break;
            } else if (cVersion > baseVersions[i]) {
                break;
            } else {
                i++;
            }
        }

        return below;
    },

    /**
     * 保存指定位数的小数点，并把尾部的0都去掉
     * @param {number} number - 待处理的数字
     * @param {number} n - 保留小数点后的位数
     * @return {string|number}
     */
    fixNumber(number, n) {
        let num = number.toFixed(n);
        let numInt = parseInt(num, 10);
        return num === numInt ? numInt : num;
    },

    /**
     * 从给定的对象上，按照指定的path规则，获取数据，如果没有，返回默认值
     * @param {object} data 指定对象
     * @param {string} path 规则
     * @param {*} defaultValue 返回的默认值
     * @return {*}
     */
    getDataOnPath(data, path, defaultValue) {
        if (!data) {
            return defaultValue;
        }
        
        const parts = path.split('.');
        let v = data;
        parts.every((k) => {
            v = v[k];
            if (v === undefined) {
                v = defaultValue;
                return false;
            }
            return true;
        });
        return v;
    },
    
    /**
     * 在给定的对象上，按照指定path规则设置数据
     * @param {object} data 指定对象
     * @param {string} path 指定规则
     * @param {*} value 设置的数值
     * @return undefined
     */
    setDataOnPath(data, path, value) {
        const parts = path.split('.');
        const lastKey = parts.pop();
        let v = data;
        parts.forEach((k) => {
            v = v[k];
            if (v === undefined) {
                return;
            }
        });
        v[lastKey] = value;
    },

    /**
     * 将字符串中的单词的首字母大写
     * @param {string} str
     * @return {string}
     */
    capitalize(str) {
        return str.replace(/\b\w/g, (l) => l.toUpperCase());
    },

    /**
     * 去掉字符串前后空格
     * @param {string} str
     * @return {string}
     */
    trim(str) {
        return str.replace(/^\s+|\s+$/g, '');
    },

    /**
     * query对象转成字符串, 如果参数是字符串直接返回
     * @param {object} q - query的对象
     * @return {string}
     */
    stringifyQuery(q) {
        if (typeof q === 'string') {
            return q;
        } 
        q = q || {};
        return Object.keys(q).map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(q[k])).join('&');
    },

    /**
     * query串转换为对象
     * @param {string} qs - query的串
     * @return {object}
     */
    parseQuery(qs) {
        qs = qs || '';
        const q = {};
        const items = qs.split('&');
        items.forEach((kv) => {
            const parts = kv.split('=');
            const k = parts[0];
            const v = parts[1];
            if (!q[k]) {
                q[k] = v;
            } else {
                q[k] = [q[k]];
                q[k].push(v);
            }
        });
        return q;
    },

    /**
     * 获取url的基础数据
     * @param {string} url - url字符串
     * @return {object}
     */
    parseUrl(url) {
        const obj = {};
        // 获取路径的hash值
        const hashSplitArr = url.split('#');
        obj.hash = hashSplitArr[1];

        const querySplitArr = hashSplitArr[0].split('?');
        obj.path = querySplitArr[0];

        if (querySplitArr[1]) {
            obj.query = this.parseQuery(querySplitArr[1]);
        }
        return obj;
    },
    
    /**
     * 读取配置文件中相应的key值
     * @param {object} origin - 数据源
     * @param {object} keyObj - 指定key
     * @return {object}
     */
    getDeepValue(origin, keyObj) {
        let result = null;
        console.log('deepValue', origin, keyObj);
        if (origin && typeof origin === 'object') {
            let code = keyObj.code,
                pageId = keyObj.pageId,
                elementId = keyObj.elementId;
            if (code) {
                result = origin[code];
                if (result && pageId) {
                    result = result[pageId];
                    if (result && elementId) {
                        result = result[elementId];
                    }
                }

            } else {
                result = origin;
            }
        }
        return result;
    },

    /**
     * 分析身份证号包含的信息，返回性别、年龄、出生日期
     * @param credentialNo 身份证号码
     * @param date 具体哪一天
     * @return {object} { gender: {string}, birthday: {string}, age: {number} }
     */
    parseCredentialNo(credentialNo, date) {
        if (!this.isValidIdCardNo(credentialNo)) {
            return null;
        }
        const idxGenderStart = credentialNo.length === 15 ? 14 : 16;
        const birthYearSpan = credentialNo.length === 15 ? 2 : 4;

        const res = {};  
        const genderFlag = 1 - credentialNo.substr(idxGenderStart, 1) % 2;  
        res.gender = genderFlag === 1 ? 'F' : 'M';  

        const year = (birthYearSpan === 2 ? '19' : '') +   credentialNo.substr(6, birthYearSpan);  
        const month = credentialNo.substr(6 + birthYearSpan, 2);  
        const day = credentialNo.substr(8 + birthYearSpan, 2);  
        res.birthday = year + '-' + month + '-' + day;  
                        
        const d = date || new Date();
        const monthFloor = ((d.getMonth() + 1) < parseInt(month, 10) || (d.getMonth() + 1) === parseInt(month, 10) && d.getDate() < parseInt(day, 10)) ? 1 : 0;  
        res.age = d.getFullYear() - parseInt(year, 10) - monthFloor;
        return res;
    },

    /**
     * 给url添加协议前缀
     * @param {string} url
     * @return {string}
     */
    normalizeResouceURL(url) {
        if (url.startsWith('https://') || url.startsWith('http://')) {
            return url;
        }
        url = global.config.RES_PATH + url;
        return url;
    },

    /**
     * 判断是否为空
     * @param {object|string|array} obj
     * @return {boolean} 是否为空
     */
    isEmpty(obj) {
        if (obj == null) return true;

        if (typeof obj === 'string' || Array.isArray(obj)) return obj.length === 0;

        return Object.keys(obj).length === 0;
    },

    /**
     * 通过webview访问pdf-viewer来打开pdf
     * @param {string/Object} optsOrKey 参数或者key，参数将会以query的形式拼接到pdf-viewer
     */
    openPdf(optsOrKey) {
        let isPrd = global.config.ENV === 'prd';
        let host = `https://static${isPrd ? '' : '-dsu'}.wesure.cn/${isPrd ? '' : global.config.ENV + 'app/'}`;
        let query = typeof optsOrKey === 'string' 
            ? `pdfKey=${optsOrKey}` 
            : Object.entries(optsOrKey).map(([key, val] ) => key + '=' + encodeURIComponent(val)).join('&');

        global.$.router.goto({
            path: '/pages/base/web/index',
            query: {
                url: encodeURIComponent(`${host}app1/pdf-viewer/index.html?${query}`)
            }
        });
    },

    /**
     * 将变量进行掩码操作
     * @param {number|string} value 需要掩码的变量
     * @param {number|string} typeOrStart 掩码类型(id,phone,name) | 开始掩码的位置(index)
     * @param {number} end 结束掩码的位置(index)
     */
    mask(value, typeOrStart, end) {
        value = value + ''; // = value.toString()
        const doMask = (str, start, end) => str.slice(0, start) + str.slice(start, end).replace(/./g, '*') + str.slice(end);

        if (typeof typeOrStart === 'number') {
            end = end || value.length;
            return doMask(value, typeOrStart, end);
        }

        switch (typeOrStart) {
            case 'id':
                return doMask(value, 3, -3);

            case 'phone':
                return doMask(value, 3, -4);
            
            case 'name':
                if (value.length < 2) return value;
                return value.length === 2
                    ? `*${value[1]}`
                    : doMask(value, 1, -1);

            default:
                return value;
        }
    }
};
